import * as THREE from "three";
import { onMounted, onBeforeUnmount } from "vue";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";

export function initRender(opt) {
  let options = {
    antialias: true,
  };
  let option = Object.assign(options, opt);
  let render = new THREE.WebGLRenderer({ antialias: option.antialias });
  render.setPixelRatio(window.devicePixelRatio);

  return render;
}

export function initCamera(opt) {
  let options = {
    fov: 75,
    aspect: 1,
    near: 1,
    far: 1000,
    position: {
      x: 200,
      y: 200,
      z: 200,
    },
    lookAt: {
      x: 0,
      y: 0,
      z: 0,
    },
  };
  let option = Object.assign(options, opt);
  let camera = new THREE.PerspectiveCamera(
    option.fov,
    option.aspect,
    option.near,
    option.far
  );
  let { position, lookAt } = option;
  camera.position.set(position.x, position.y, position.z);
  camera.lookAt(lookAt.x, lookAt.y, lookAt.z);
  return camera;
}

export function initControl(camera, render, sence, callback) {
  let control = new OrbitControls(camera, render.domElement);
  let fn = callback ? callback : () => render.render(sence, camera);
  control.addEventListener("change", fn);
  controls.enableDamping = true;
  return control;
}

export function axesHelper(long = 500) {
  let axes = new THREE.AxesHelper(long);
  return axes;
}

export function gridHelper(w = 1000, h = 100) {
  return new THREE.GridHelper(w, h);
}

export function initLight(type, color = "#fff", q = 1) {
  if (type == "ambient") return new THREE.AmbientLight(color, q);
  if (type == "point") return new THREE.PointLight(color, q);
  if (type == "directional") return new THREE.DirectionalLight(color, q);
  if (type == "spot") return new THREE.SpotLight(color, q);
}

export function initAmbient(color = "#fff", q = 1) {
  return new THREE.AmbientLight(color, q);
}

export default function useThree(el, opt) {
  let options = {
    control: true,
    axesHelper: false,
    camera: {},
    render: {},
  };
  let option = Object.assign(options, opt);
  let Scene = new THREE.Scene();

  let camera = initCamera(option.camera);
  let render = initRender(option.render);
  let control = option.control ? initControl(camera, render, Scene) : null;
  if (option.axesHelper) {
    let axes = axesHelper();
    Scene.add(axes);
  }

  render.setSize(el.offsetWidth, el.offsetHeight);
  el.appendChild(render.domElement);
  render.render(Scene, camera);

  function resize() {
    render.setSize(el.offsetWidth, el.offsetHeight);
    camera.aspect = el.offsetWidth / el.offsetHeight;
    camera.updateProjectionMatrix();
    render.setPixelRatio(window.devicePixelRatio);
    render.render(Scene, camera);
  }

  window.addEventListener("resize", resize);

  onBeforeUnmount(() => {
    Scene.remove();
    render.dispose();
    control.dispose();
    window.removeEventListener("resize", resize);
  });

  return { Scene, camera, render, control };
}
